#include "laurin-window.h"
#include "laurin-80211-networks-model.h"
#include <glibmm/thread.h>
#include <gtkmm/stock.h>
#include <gtkmm/messagedialog.h>
#include <gtkmm/toolbar.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/dialog.h>
#include <gtkmm/aboutdialog.h>
#include <gtkmm/treeview.h>
#include <gtkmm/box.h>
#include <gtkmm/statusbar.h>
#include <gtkmm/action.h>
#include <gtkmm/actiongroup.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/combobox.h>
#include <gtkmm/entry.h>
#include <gtkmm/frame.h>
#include <gtkmm/main.h>
#include <gtkmm/liststore.h>
#include <gdkmm/pixbuf.h>


#define UI_FILE  "/mnt/ExecWorkspace/laurin-gui/laurin/share/laurin-gui.ui"
#define ACTIONS_FILE  "/mnt/ExecWorkspace/laurin-gui/laurin/share/menubar.xml"
#define ICON_FILE "/mnt/ExecWorkspace/laurin-gui/laurin/share/laurin-icon.png"

LaurinWindow::~LaurinWindow(){}


bool LaurinWindow::initialize(int argc, char** argv)
{
	_app = NULL;

	if(!Glib::thread_supported())
		Glib::thread_init();

	_kit = new Gtk::Main(argc, argv);

	_builder =  Gtk::Builder::create_from_file(UI_FILE);
	_builder->get_widget("laurin-root-gui", _app);

	_builder->get_widget("status-progressbar", _progress_bar);
	_progress_bar->set_fraction(0.0);

	if(!_app)
		return false;

	_app->set_icon_from_file(ICON_FILE);

	setActions();

	return true;
}


void LaurinWindow::run()
{
	setMenuForRunningStatus(false);
	setStatus("Laurin Ready");
	_kit->run(*_app);
}


void LaurinWindow::setActions()
{
	Glib::RefPtr<Gtk::ActionGroup> actions = Gtk::ActionGroup::create();

	// menu file
	actions->add(Gtk::Action::create("MenuFile", "_File"));

	actions->add(Gtk::Action::create("Run", Gtk::Stock::CONNECT),
			  sigc::mem_fun(*this, &LaurinWindow::on_action_file_run) );

	actions->add(Gtk::Action::create("Stop", Gtk::Stock::DISCONNECT),
				  sigc::mem_fun(*this, &LaurinWindow::on_action_file_stop) );

	actions->add(Gtk::Action::create("Exit", Gtk::Stock::QUIT),
				  sigc::mem_fun(*this, &LaurinWindow::on_action_file_exit) );


	//MENU BAR

	// menu edit
	actions->add(Gtk::Action::create("MenuEdit", "_Edit"));
	actions->add(Gtk::Action::create("Preferences", Gtk::Stock::PREFERENCES),
			sigc::mem_fun(*this, &LaurinWindow::on_action_edit_preferences));

	// menu view
	actions->add(Gtk::Action::create("MenuView", "_View"));

	actions->add(Gtk::Action::create("NetView", Gtk::Stock::NETWORK),
				sigc::mem_fun(*this, &LaurinWindow::on_action_view_network));


	actions->add(Gtk::Action::create("DevicesView", Gtk::Stock::FIND),
				sigc::mem_fun(*this, &LaurinWindow::on_action_view_devices));


	// menu help
	actions->add(Gtk::Action::create("MenuHelp", "_Help"));
	actions->add(Gtk::Action::create("About", Gtk::Stock::ABOUT),
				  sigc::mem_fun(*this, &LaurinWindow::on_action_help_about) );



	_ui_manager = Gtk::UIManager::create();
	_ui_manager->insert_action_group(actions);
	_ui_manager->add_ui_from_file(ACTIONS_FILE);


	Gtk::VBox* menubarc = NULL;
	_builder->get_widget("menubar-container", menubarc);

	menubarc->pack_start(*(_ui_manager->get_widget("/MenuBar")),false, true, 0);


	//TOOLBAR
	Gtk::VBox* toolbarc = NULL;
	Gtk::Toolbar* toolbar = (Gtk::Toolbar*) _ui_manager->get_widget("/ToolBar");

	_builder->get_widget("toolbar-container", toolbarc);
	toolbar->set_toolbar_style(Gtk::TOOLBAR_ICONS);

	toolbarc->pack_start(*toolbar, false, true, 0);


}


void LaurinWindow::setStatus(const Glib::ustring& status)
{
	Gtk::Statusbar* bar = NULL;
	_builder->get_widget("main-statusbar", bar);
	bar->push(status);
}


void LaurinWindow::removeLastStatus()
{
	Gtk::Statusbar* bar = NULL;
	_builder->get_widget("main-statusbar", bar);
	bar->pop();
}


void LaurinWindow::setMenuForRunningStatus(bool running)
{
	_ui_manager->get_action("/ui/MenuBar/MenuFile/Run")->set_sensitive(!running);
	_ui_manager->get_action("/ui/MenuBar/MenuFile/Stop")->set_sensitive(running);
	_ui_manager->get_action("/ui/ToolBar/NetView")->set_sensitive(running);
	_ui_manager->get_action("/ui/ToolBar/DevicesView")->set_sensitive(running);
}


void LaurinWindow::setProgressBarStatus(bool running)
{
	_progress_bar->set_sensitive(running);

	if(running)
	{
		_timeout_connection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &LaurinWindow::on_progress_timeout), 100);
	}
	else
	{
		_timeout_connection.disconnect();
		_progress_bar->set_fraction(0.0);
	}
}


void LaurinWindow::setOperationComplete()
{
	_app->set_sensitive(false);
	setMenuForRunningStatus(false);
	setProgressBarStatus(false);
	removeLastStatus();

	Gtk::TreeView* networks_view = NULL;
	_builder->get_widget("networks-tree", networks_view);

	_controller.fillModel(&_devices_model);
	networks_view->set_model(_devices_model.getStore());

	_app->set_sensitive(true);

}


void LaurinWindow::on_action_edit_preferences()
{

	Gtk::Dialog* preferences = NULL;
	_builder->get_widget("laurin-preferences-dialog", preferences);

	preferences->set_icon_from_file(ICON_FILE);
	preferences->signal_response().connect(sigc::mem_fun(*this, &LaurinWindow::on_edit_preferences_response));
	_temp_options = _controller.getOptions();


	// get the avaible devices and create the model for the combobox
	std::list<Glib::ustring> aux = getAvaibleDevices();


	Gtk::TreeModelColumn<Glib::ustring> col_model;
	Gtk::TreeModel::ColumnRecord record;
	record.add(col_model);
	Glib::RefPtr<Gtk::ListStore> devstore = Gtk::ListStore::create(record);

	std::list<Glib::ustring>::iterator b = aux.begin();
	std::list<Glib::ustring>::iterator e = aux.end();

	// save the position of current device's names
	Gtk::TreeModel::iterator nd;
	Gtk::TreeModel::iterator md;

	while(b != e)
	{
		Gtk::TreeModel::iterator iter =  devstore->prepend();
		Gtk::TreeModel::Row row = *iter;

		row.set_value(0, *b);

		if(_temp_options.network_device_name == *b)
		{
			nd = iter;
		}

		if(_temp_options.monitor_device_master_name == *b)
		{
			md = iter;
		}

		b++;
	}





	// discover NETWORK page
	Gtk::CheckButton* ndc = NULL;
	Gtk::Frame* nof = NULL;
	_builder->get_widget("network-discover-check", ndc );
	_builder->get_widget("network-options-frame", nof);
	ndc->set_active(_temp_options.operation_mode & LAURIN_DISCOVER_NETWORK_CLIENTS_MODE);
	nof->set_sensitive(_temp_options.operation_mode & LAURIN_DISCOVER_NETWORK_CLIENTS_MODE);

	// add signal handler
	ndc->signal_toggled().connect(sigc::mem_fun(*this, &LaurinWindow::on_edit_preferences_enable_network_discover));


	Gtk::SpinButton* nrts = NULL;
	_builder->get_widget("network-reply-timeout-spin", nrts);

	nrts->set_value((double)_temp_options.network_frame_timeout);
	nrts->signal_changed().connect(sigc::mem_fun(*this, &LaurinWindow::on_edit_preferences_change_network_timeout));


	Gtk::ComboBox* ndnc = NULL;
	_builder->get_widget("network-device-name-combobox", ndnc);

	ndnc->clear();
	ndnc->set_model(devstore);
	ndnc->pack_start(col_model);


	if(nd)
		ndnc->set_active(nd);
	else
		ndnc->set_active(0);

	ndnc->signal_changed().connect(sigc::mem_fun(*this, &LaurinWindow::on_edit_preferences_change_network_device));



	// discover DEVICES page
	Gtk::CheckButton* ddc = NULL;
	Gtk::Frame* dof = NULL;
	_builder->get_widget("devices-discover-check", ddc);
	_builder->get_widget("devices-options-frame", dof);
	ddc->set_active(_temp_options.operation_mode & LAURIN_DISCOVER_DEVICES_MODE);
	dof->set_sensitive(_temp_options.operation_mode & LAURIN_DISCOVER_DEVICES_MODE);

	ddc->signal_toggled().connect(sigc::mem_fun(*this, &LaurinWindow::on_edit_preferences_enable_devices_discover));

	Gtk::SpinButton*  dmfr = NULL;
	_builder->get_widget("devices-max-frame-spin", dmfr);

	dmfr->set_value((double) _temp_options.discover_max_frame);
	dmfr->signal_changed().connect(sigc::mem_fun(*this, &LaurinWindow::on_edit_preferences_change_max_frame));

	Gtk::ComboBox* dmdc = NULL;
	_builder->get_widget("devices-master-device-combobox", dmdc);

	dmdc->clear();
	dmdc->set_model(devstore);
	dmdc->pack_start(col_model);

	if(md)
		dmdc->set_active(md);
	else
		dmdc->set_active(0);

	dmdc->signal_changed().connect(sigc::mem_fun(*this, &LaurinWindow::on_edit_preferences_change_master_device));

	Gtk::Entry* dvde = NULL;
	_builder->get_widget("devices-virtual-device-entry", dvde);

	dvde->set_text(_temp_options.monitor_device_name);
	dvde->signal_changed().connect(sigc::mem_fun(*this, &LaurinWindow::on_edit_preferences_change_virtual_device_name));




	// location page
	Gtk::CheckButton* lc = NULL;
	_builder->get_widget("location-check", lc);
	lc->set_active(_temp_options.operation_mode & LAURIN_LOCATION_MODE);
	lc->signal_toggled().connect(sigc::mem_fun(*this, &LaurinWindow::on_edit_preferences_enable_location));

	preferences->run();
}


void LaurinWindow::on_action_file_exit()
{
	_kit->quit();
}


void LaurinWindow::on_action_file_run()
{

	if(_controller.isRunning())
		return;

	_app->set_sensitive(false);

	if(_controller.start())
	{
		setMenuForRunningStatus(true);
		setProgressBarStatus(true);
		setStatus("Laurin Started");
	}
	else
		Gtk::MessageDialog(*_app, "Error on start modules!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true).run();


	_app->set_sensitive(true);

}


void LaurinWindow::on_action_file_stop()
{
	if(!_controller.isRunning())
		return;

	_controller.stop();
	setOperationComplete();
}


void LaurinWindow::on_action_help_about()
{
	Gtk::AboutDialog* dialog = NULL;
	_builder->get_widget("laurin-about-dialog", dialog);

	dialog->set_icon_from_file(ICON_FILE);
	dialog->set_logo(Gdk::Pixbuf::create_from_file(ICON_FILE));
	dialog->signal_response().connect(sigc::mem_fun(*this, &LaurinWindow::on_about_dialog_response));
	dialog->run();
}


void LaurinWindow::on_about_dialog_response(int response)
{
	Gtk::AboutDialog* dialog = NULL;
	_builder->get_widget("laurin-about-dialog", dialog);
	dialog->hide();
}


void LaurinWindow::on_edit_preferences_enable_location()
{
	Gtk::CheckButton* button = NULL;
	_builder->get_widget("location-check", button);

	if(button->get_active())
		_temp_options.operation_mode |= LAURIN_LOCATION_MODE;

	else
		_temp_options.operation_mode ^= LAURIN_LOCATION_MODE;
}


void LaurinWindow::on_edit_preferences_enable_devices_discover()
{
	Gtk::CheckButton* button = NULL;
	Gtk::Frame* frame = NULL;

	_builder->get_widget("devices-discover-check", button);
	_builder->get_widget("devices-options-frame", frame);

	if(button->get_active())
	{
		_temp_options.operation_mode |= LAURIN_DISCOVER_DEVICES_MODE;
		frame->set_sensitive(true);
	}
	else
	{
		_temp_options.operation_mode ^= LAURIN_DISCOVER_DEVICES_MODE;
		frame->set_sensitive(false);
	}
}


void LaurinWindow::on_edit_preferences_enable_network_discover()
{
	Gtk::CheckButton* button = NULL;
	Gtk::Frame* frame = NULL;
	_builder->get_widget("network-discover-check", button);
	_builder->get_widget("network-options-frame", frame);

	if(button->get_active())
	{
		_temp_options.operation_mode |= LAURIN_DISCOVER_NETWORK_CLIENTS_MODE;
		frame->set_sensitive(true);
	}

	else
	{
		_temp_options.operation_mode ^= LAURIN_DISCOVER_NETWORK_CLIENTS_MODE;
		frame->set_sensitive(false);
	}
}


void LaurinWindow::on_edit_preferences_response(int response)
{
	Gtk::Dialog* dialog = NULL;
	_builder->get_widget("laurin-preferences-dialog", dialog);

	if(response == Gtk::RESPONSE_APPLY)
	{
		if(_temp_options.areValid())
			_controller.setOptions(_temp_options);

		else
		{
			Gtk::MessageDialog message(*dialog, "Configuration contains errors. It will not be saved!", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
			message.run();
		}

		dialog->hide();
	}
	else if(response == Gtk::RESPONSE_CANCEL)
		dialog->hide();

}


void LaurinWindow::on_edit_preferences_change_max_frame()
{
	Gtk::SpinButton*  dmfr = NULL;
	_builder->get_widget("devices-max-frame-spin", dmfr);

	_temp_options.discover_max_frame = (int) dmfr->get_value();
}


void LaurinWindow::on_edit_preferences_change_network_timeout()
{
	Gtk::SpinButton* nrts = NULL;
	_builder->get_widget("network-reply-timeout-spin", nrts);

	_temp_options.network_frame_timeout = (int) nrts->get_value();
}


void LaurinWindow::on_edit_preferences_change_virtual_device_name()
{
	Gtk::Entry* dvde = NULL;
	_builder->get_widget("devices-virtual-device-entry", dvde);

	_temp_options.monitor_device_name = dvde->get_text();
}


void LaurinWindow::on_edit_preferences_change_master_device()
{
	Gtk::ComboBox* dmdc = NULL;
	_builder->get_widget("devices-master-device-combobox", dmdc);

	Gtk::TreeModel::iterator iter =  dmdc->get_active();
	if(bool(iter))
	{
		Gtk::TreeModel::Row row = *iter;
		row.get_value(0, _temp_options.monitor_device_master_name);
	}
}


void LaurinWindow::on_edit_preferences_change_network_device()
{
	Gtk::ComboBox* ndnc = NULL;
	_builder->get_widget("network-device-name-combobox", ndnc);


	Gtk::TreeModel::iterator iter =  ndnc->get_active();
	if(iter)
	{
		Gtk::TreeModel::Row row = *iter;
		row.get_value(0, _temp_options.network_device_name);
	}
}


void LaurinWindow::on_action_view_devices()
{

}


void LaurinWindow::on_action_view_network()
{

}


bool LaurinWindow::on_progress_timeout()
{
	_progress_bar->pulse();


	if(_controller.isRunning())
		return true;

	setOperationComplete();
	return false;
}
